home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / pccts.zip / begtut.ms next >
Text File  |  1992-12-08  |  38KB  |  1,154 lines

  1. .de iH
  2. \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
  3. \\.XS
  4. .if \\n(NS-4     
  5. .if \\n(NS-3     
  6. .if \\n(NS-2     
  7. .if \\n(NS-1     
  8. \\*(SN \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
  9. \\.XE
  10. ..
  11. .de 1s
  12. .nr PS 12
  13. .nr VS 13
  14. .br
  15. .LP
  16. ..
  17. .de 2s
  18. .nr PS 12
  19. .nr VS 16
  20. .br
  21. .LP
  22. ..
  23. .de cB
  24. .nr PS 10
  25. .nr VS 11
  26. .br
  27. .LP
  28. .KS
  29. .LD
  30. .ft CW
  31. ..
  32. .de cE
  33. .DE
  34. .KE
  35. .2s
  36. .ft R
  37. ..
  38. .EH 'PCCTS Introductory Tutorial 1.0x'
  39. .OH 'PCCTS Introductory Tutorial 1.0x'
  40. .EF '''Page %'
  41. .OF '''Page %'
  42. .ds d $
  43. .EQ
  44. delim $$
  45. .EN
  46. .TL
  47. \s+4Introductory Tutorial
  48. .sp 2
  49. .br
  50. PCCTS 1.0x\s-4
  51. .AU
  52. Terence Parr, Hank Dietz, Will Cohen
  53. .AI
  54. School of Electrical Engineering
  55. Purdue University
  56. West Lafayette, IN  47907
  57. \fIFall 1992\fP
  58. .sp 1
  59. \f(CWparrt@ecn.purdue.edu\fP
  60. \f(CWhankd@ecn.purdue.edu\fP
  61. \f(CWcohenw@ecn.purdue.edu\fP
  62. .2s
  63. .LP
  64. .br
  65. .QP
  66. The Purdue Compiler-Construction Tool Set (PCCTS) is a set of public
  67. domain software tools designed to facilitate the implementation of
  68. compilers and other translation systems.  In many ways, PCCTS is
  69. similar to a highly integrated version of YACC and LEX; where ANTLR
  70. (ANother Tool for Language Recognition) corresponds to YACC and DLG
  71. (DFA-based Lexical analyzer Generator) functions like LEX.  However,
  72. PCCTS has many additional features which make it easier to use for a
  73. wide range of translation problems.
  74. .QP
  75. This document introduces the basic functionality of PCCTS by example.
  76. The user need not be familiar with parsing theory or other compiler tools,
  77. but any familiarity reduces the learning curve substantially.  The PCCTS
  78. reference manual is a necessary supplement to this tutorial as information
  79. here regarding PCCTS structures and operation is incomplete.
  80. .LP
  81. .bp
  82. .NH
  83. .iH Introduction
  84. .PP
  85. PCCTS allows the user to describe languages (e.g. programming language,
  86. OS shell, game, editor); from such a description, a C program is generated that
  87. recognizes and, optionally, translates phrases in that language.
  88. The user must specify the following:
  89. .IP \fI(i)\fP
  90. How the input stream is to be broken up into lexemes (tokens) which
  91. comprise the vocabulary of the language.
  92. .IP \fI(ii)\fP
  93. How the tokens are to be grouped; i.e. what structure/grammar is to be
  94. applied to the token stream.
  95. .IP \fI(iii)\fP
  96. C actions which perform a user-specified translation.  Along with
  97. this specification, the user must also describe token attributes\(emobjects
  98. that actions use to communicate with the lexical analysis phase of translation.
  99. .LP
  100. Similarly, this tutorial is broken up into sections on lexical
  101. analysis, syntactic analysis, and actions/translation.
  102. .NH
  103. .iH Lexical Analysis
  104. .PP
  105. Before understanding a phrase in English, one must separate the stream
  106. of characters into a stream of words; e.g. the phrase: \*Qthisisveryhardtoread\*U
  107. accentuates this fact\(emrecognition cannot easily be done from a character
  108. stream, only from word/token streams.
  109. .PP
  110. Compilers and other translators are very strict about this
  111. \*Qtokenization\*U and generally describe tokens via \fIregular
  112. expressions\fR\(emexpressions that describe sets of character
  113. sequences.  The regular expressions are, in fact, language
  114. descriptions as well.  For example, \f(CWhello\fR is a regular
  115. expression that recognizes a sequence of five characters; namely, the
  116. word: \*Qhello\*U.  To inform PCCTS that \*Qhello\*U is to be a word
  117. in the vocabulary of your language, the following description would be
  118. placed in your grammar file.
  119. .cB
  120. #token LABEL "hello"
  121. .cE
  122. .LP
  123. where \f(CWLABEL\fR is some label (C \f(CW#define\fP) that you want
  124. associated with that token.  To test regular expressions in PCCTS, let
  125. us form a simple, complete description which recognizes \*Qhello\*U
  126. (we will use this description as a base for all examples in this
  127. section):
  128. .cB
  129. #header <<#include "charbuf.h">>
  130.  
  131. <<main() { ANTLR(a(), stdin); }>>
  132.  
  133. #token WORD "hello"
  134.  
  135. a : WORD ;
  136. .cE
  137. .LP
  138. This is a minimal description in that it contains everything needed
  139. for PCCTS to generate an executable (actually, to generate all C files
  140. needed for the C compiler to generate an executable).  The
  141. \f(CW#header <<...>>\fP instruction informs PCCTS that the C code inside the
  142. \f(CW<<...>>\fP action is necessary to define attributes and to
  143. compile the actions found elsewhere; for this section, we will ignore
  144. its significance.  The second action gives a main program that
  145. specifies where C is to begin execution.  It contains one statement
  146. which asks ANTLR to begin parsing at rule \f(CWa\fP.  The third
  147. instruction defines a token \f(CWhello\fP.  The fourth component of
  148. this description is a rule definition.  Rules definitions have the
  149. form:
  150. .cB
  151. \fIrule\fP: $alternative sub 1$ | $alternative sub 2$ | ... | $alternative sub n$ ;
  152. .cE
  153. .LP
  154. where each alternative is a sequence of grammatical structures that
  155. are to be matched\(emone of possible structures is a simple token
  156. reference (\f(CWWORD\fP, in our case).  Therefore, rule \f(CWa\fP
  157. says, \*Qmatch the token identified as \f(CWWORD\fP on the input
  158. stream\*U.  The C function generated for rule \f(CWa\fP asks the
  159. lexical analyzer, generated by PCCTS, to collect characters until it
  160. sees a complete token.  Each token in the vocabulary is given a unique
  161. number which the lexical analyzer returns to indicate what token was
  162. just matched.  Function \f(CWa()\fP then verifies that the number
  163. associated with \f(CWWORD\fP is indeed returned by the lexical
  164. analyzer.
  165. .PP
  166. The above example can be tested via the following sequence of commands:
  167. .cB
  168. antlr -gk t.g
  169. dlg -i parser.dlg scan.c
  170. cc -I../h -o t t.c scan.c err.c
  171. .cE
  172. The first command generates the parser, \f(CWt.c\fP, the lexical
  173. description, \f(CWparser.dlg\fP, and a support file, \f(CWerr.c\fP.
  174. The second command converts the lexical description to a C file that
  175. constitutes our scanner (lexical analyzer).  The third command
  176. compiles all C files needed to generate the executable (the
  177. \f(CW-I../h\fP option tells the C compiler where to look for the
  178. standard PCCTS include files; you will have to change this to where
  179. the PCCTS include files are located).  The output on our UNIX system
  180. looks like this (assuming the example is in file \f(CWt.g\fP):
  181. .cB
  182. % antlr -gk t.g
  183. Antlr parser generator   Version 1.06   1989-1992
  184. % dlg -i parser.dlg scan.c
  185. dlg  Version 1.0   1989, 1990, 1991
  186. % cc -I../h -o t t.c scan.c err.c
  187. .cE
  188. .LP
  189. To test the grammar file, run the executable:
  190. .cB
  191. % t
  192. hello
  193. .cE
  194. .LP
  195. No error message is generated and \f(CWt\fP terminates successfully.
  196. If a token not in the vocabulary of our language is typed, an error
  197. message appears.  We have only one word in our vocabulary, and hence,
  198. anything other than \*Qhello\*U generates an error.
  199. .cB
  200. % t
  201. bob
  202. invalid token near line 1 (text was 'b')
  203. invalid token near line 1 (text was 'o')
  204. invalid token near line 1 (text was 'b')
  205. invalid token near line 1 (text was '
  206. ')
  207. ^Dline 1: syntax error at "EOF" missing WORD
  208. .cE
  209. .LP
  210. The first \*Qinvalid token\*U errors are from the scanner, the last
  211. message is from the parser (function \f(CWa()\fP) indicating that
  212. end-of-file was found when a \f(CWWORD\fP was expected.  \f(CWEOF\fP
  213. was returned by the scanner because \f(CWbob\fP was ignored and
  214. end-of-file appeared immediately afterwards; \f(CWEOF\fP is a
  215. predefined token in any PCCTS vocabulary.
  216. .PP
  217. Adding more tokens to your language's vocabulary is easy\(emsimply add more
  218. \f(CW#token\fP definitions.  Consider this new example:
  219. .cB
  220. #token    "\e "     <<zzskip();>>            /* ignore blanks */
  221. #token    "\et"     <<zzskip();>>            /* ignore tabs */
  222. #token    "\en"     <<zzline++; zzskip();>>  /* ignore newlines */
  223. #token A  "apple"
  224. #token P  "pear"
  225. .cE
  226. .LP
  227. This example introduces lexical actions\(emactions that are executed
  228. upon recognition of a particular regular expression.  For most language
  229. descriptions, lexical actions are not used except to tell the scanner
  230. to skip a token or continue looking for more characters.
  231. \f(CWzzskip()\fP is a standard PCCTS function (generally, PCCTS
  232. variables/functions/defines are prefixed with \f(CWzz\fP to avoid name
  233. collisions with user variables) which forces the scanner to ignore the
  234. currently matched token and to try to find another.  Essentially, the
  235. first three token definitions here tell the scanner that it is to
  236. ignore white space, but to increment the current line number when it
  237. sees a newline.  The fourth and fifth definitions introduce two words
  238. into our vocabulary.  Notice that only the last two have labels
  239. associated with them.  Any \f(CW#token\fP instruction may give a
  240. label, but they are not necessary.  Labels are handy when you want an
  241. action to refer to the value (token number) of a particular token;
  242. also, when a regular expression is complicated or confusing, often it
  243. is better to use a label throughout your grammar rather than repeating
  244. the regular expression.  To illustrate this, we present the following
  245. four equivalent partial PCCTS descriptions:
  246. .IP \fI(i)\fP
  247. Repeated use of labels.
  248. .cB
  249. #token A "apple"
  250. #token P "pear"
  251.  
  252. a : A P
  253.   | P A
  254.   ;
  255. .cE
  256. .IP \fI(ii)\fP
  257. Repeated use of expressions.
  258. .cB
  259. #token "apple"
  260. #token "pear"
  261.  
  262. a : "apple" "pear"
  263.   | "pear" "apple"
  264.   ;
  265. .cE
  266. .IP \fI(iii)\fP
  267. Repeated use of implicitly-defined expressions.
  268. .cB
  269. a : "apple" "pear"
  270.   | "pear" "apple"
  271.   ;
  272. .cE
  273. .IP \fI(iv)\fP
  274. Mixed use of labels and expressions.
  275. .cB
  276. #token A  "apple"
  277. #token P  "pear"
  278.  
  279. a : "apple" P
  280.   | "pear" A
  281.   ;
  282. .cE
  283. .LP
  284. Each unique token regular-expression string in PCCTS gets its own token
  285. number.  Token labels are words that begin with a uppercase letter whereas
  286. rules begin with lowercase letters.  Repeating the same token string in a
  287. grammar merely refers to the same token; strings can only appear once in
  288. \f(CW#token\fP definitions, however, as this instruction attempts to define
  289. a new token.  An implicitly-defined token is one that is referenced but that
  290. has no formal \f(CW#token\fP instruction.  In fact, we use the
  291. \f(CW#token\fP only when the expression is long, when a lexical action must
  292. be attached, or when a label is required (so that a C action can refer
  293. to it).
  294. .PP
  295. Each rule \f(CWa\fP above indicates that either \f(CWapple\fP followed by
  296. \f(CWpear\fP is to be matched or \f(CWpear\fP followed by \f(CWapple\fP
  297. is to be matched.
  298. .PP
  299. Once again, let's test this vocabulary description with a complete,
  300. executable example:
  301. .cB
  302. #header <<#include "charbuf.h">>
  303.  
  304. <<main() { ANTLR(a(), stdin); }>>
  305.  
  306. #token    "\e "     <<zzskip();>>            /* ignore blanks */
  307. #token    "\et"     <<zzskip();>>            /* ignore tabs */
  308. #token    "\en"     <<zzline++; zzskip();>>  /* ignore newlines */
  309.  
  310. a : "apple" "pear"
  311.   | "pear" "apple"
  312.   ;
  313. .cE
  314. .LP
  315. To build the executable, we proceed as before:
  316. .cB
  317. % antlr -gk t.g
  318. Antlr parser generator   Version 1.06   1989-1992
  319. % dlg -i parser.dlg scan.c
  320. dlg  Version 1.0   1989, 1990, 1991
  321. % cc -g -I../h -o t t.c scan.c err.c
  322. .cE
  323. .LP
  324. To test the example, type:
  325. .cB
  326. % t
  327. apple
  328.      pear
  329. .cE
  330. No error is reported due to the validity of the input.  Note that the
  331. newline and the spaces were ignored because of the \f(CWzzskip()\fP actions
  332. associated with our token definitions for white space.  To ensure that
  333. \f(CWt\fP is actually doing something useful, try:
  334. .cB
  335. % t
  336. apple apple
  337. line 2: syntax error at "apple" missing pear
  338. ^D% 
  339. .cE
  340. .LP
  341. PCCTS generates parsers that automatically report errors and try to
  342. resynchronize the parser; hence, in this case, a control-D (\f(CW^D\fP) is
  343. necessary to terminate the program because \f(CWt\fP is looking for another
  344. token with which to resynchronize.  Because of the \f(CWzzline++\fP
  345. statement in the action for newline, the error is correctly reported on line
  346. 2.
  347. .PP
  348. The regular expressions used in the above examples are simple and do not use
  349. any of the \fImeta-characters\fP or regular expression operators.  Before
  350. presenting a more realistic example, we illustrate the use of some useful
  351. regular expression meta-characters (for a complete description see PCCTS
  352. documentation):
  353. .IP \f(CW@\fR
  354. \f(CWEOF\fP character
  355. .IP \f(CW\et\fR
  356. tab character
  357. .IP \f(CW\en\fR
  358. newline character
  359. .IP \f(CW\e\fP\fIc\fR
  360. character escape; used to obtain actual character for meta-characters
  361. .IP \f(CW(\fIe\f(CW)\fR
  362. keep expression \fIe\fP as an indivisible group
  363. .IP \f(CW[\fIc\f(CW]\fR
  364. match one character from list \fIc\fP
  365. .IP \f(CW[\fIx\f(CW-\fIy\f(CW]\fR
  366. match one character from range \fIx\fP to \fIy\fP
  367. .IP \f(CW~[\fIc\f(CW]\fR
  368. match one character not in list \fIc\fP
  369. .IP \f(CW{\fIe\f(CW}\fR
  370. expression \fIe\fP is optional
  371. .IP \fIe\f(CW*\fR
  372. match zero or more of \fIe\fP
  373. .IP \fIe\f(CW+\fR
  374. match one or more of \fIe\fP
  375. .IP \fIe\f(CW|\fIf\fR
  376. match either expression \fIe\fP \fBor\fR \fIf\fP
  377. .LP
  378. Naturally, the above operators and meta-characters can be used in many
  379. combinations to produce very complicated expressions.  To illustrate more
  380. complex expressions, we define the vocabulary of a calculator (ignoring
  381. white space for the moment).
  382. .cB
  383. #token NUM "[0-9]+"
  384. #token VAR "[a-zA-Z][a-zA-Z0-9]*"
  385. #token     "\e("
  386. #token     "\e)"
  387. #token     "\e+"
  388. #token     "\e-"
  389. #token     "\e*"
  390. #token     "/"
  391. .cE
  392. .LP
  393. A number is defined as a sequence of one or more decimal digits.
  394. Variables begin with an upper or lowercase letter, but can otherwise
  395. contain digits as well; note that \f(CW*\fP is used rather than
  396. \f(CW+\fP for variables because \f(CW+\fP would force \f(CWVAR\fP to
  397. recognize at least two characters.  This calculator has some tokens in
  398. its vocabulary that are identical to those of the regular expressions,
  399. so these must be escaped to tell the scanner to look for those actual
  400. characters.  To create an executable, we form a grammar which accepts
  401. one of the words in the vocabulary:
  402. .cB
  403. #header <<#include "charbuf.h">>
  404.  
  405. <<main() { ANTLR(a(), stdin); }>>
  406.  
  407. #token     "\e "     <<zzskip();>>            /* ignore blanks */
  408. #token     "\et"     <<zzskip();>>            /* ignore tabs */
  409. #token     "\en"     <<zzline++; zzskip();>>  /* ignore newlines */
  410. .cE
  411. .cB
  412. #token NUM "[0-9]+"
  413. #token VAR "[a-zA-Z][a-zA-Z0-9]*"
  414. #token     "\e("
  415. #token     "\e)"
  416. #token     "\e+"
  417. #token     "\e-"
  418. #token     "\e*"
  419. #token     "/"
  420.  
  421. a : NUM | VAR | "\e(" | "\e)" | "\e+" | "\e-" | "\e*" | "/" ;
  422. .cE
  423. .LP
  424. As before, we create the executable with (assuming the example is in
  425. \f(CWt.g\fR):
  426. .cB
  427. antlr -gk t.g
  428. dlg -i parser.dlg scan.c
  429. cc -g -I../h -o t t.c scan.c err.c
  430. .cE
  431. .LP
  432. The executable, \f(CWt\fP, will recognize any one token from our
  433. vocabulary.  The next section discusses how one employs rules to specify
  434. valid, structured sequences; i.e. how one defines the syntax of a language.
  435. .NH
  436. .iH Syntactic Analysis
  437. .PP
  438. The syntax of a language is the grammatical structure which summarizes
  439. the set of valid phrases in that language.  Because one cannot
  440. normally delineate all possible sentences, languages are described via
  441. a set of rules which obey the laws of a \fImeta-language\fP, which is
  442. literally a \*Qlanguage to describe languages\*U just as the syntax of
  443. regular expressions represents a language.  This section describes the
  444. format of a PCCTS language description\(emthe syntax of PCCTS rules
  445. and how they may be used to impose a structure upon a stream of input
  446. tokens.
  447. .PP
  448. The basic template used to build a grammar is:
  449. .nf
  450. .LP
  451.     \f(CW#header\fP \fIaction\fP
  452. .br
  453.     \fIaction(s)\fR and/or \f(CW#token\fR \fIdefinition(s)
  454. .br
  455.     rule(s)
  456. .br
  457.     action(s)\fR and/or \f(CW#token\fR \fIdefinition(s)
  458. .fi
  459. .LP
  460. To compile, all grammars must define a number of things inside the
  461. \f(CW#header\fP action; this instruction is not optional and must
  462. appear first in your file.  The rest of the file is basically a
  463. sequence of user actions, token and rule definitions\(emexcept that
  464. actions, not contained within rules, must be placed before or after
  465. the rule definitions.
  466. .PP
  467. Rules have the basic form:
  468. .cB
  469. \fIrule\fP: $alternative sub 1$ | $alternative sub 2$ | ... | $alternative sub n$ ;
  470. .cE
  471. .LP
  472. where $alternative sub i$ is a sequence of the following elements:
  473. .IP \fItoken\fP\ \ 
  474. Match \fItoken\fP on the input stream.
  475. .IP \fIrule\fP\ \ 
  476. Visit \fIrule\fP and match whatever is specified.
  477. .IP \fIaction\fR\ \ 
  478. Execute C \fIaction\fP.
  479. .IP "\f(CW($a sub 1$ | $a sub 2$ | ... | $a sub n$)\fR"
  480. Introduce a subrule\(emmatch one $a sub i$.
  481. .IP "\f(CW{$a sub 1$ | $a sub 2$ | ... | $a sub n$}\fR"
  482. Introduce an optional subrule; match one $a sub i$ or none.
  483. .IP "\f(CW($a sub 1$ | $a sub 2$ | ... | $a sub n$)*\fR"
  484. Conditionally match any sequence of $a sub i$'s.
  485. .IP "\f(CW($a sub 1$ | $a sub 2$ | ... | $a sub n$)+\fR"
  486. Match any sequence of $a sub i$'s.
  487. .LP
  488. Examples of rule definitions are:
  489. .cB
  490. w   :   WORD ("," WORD)*
  491.     ;
  492. .cE
  493. .LP
  494. where rule \f(CWw\fP matches a list of comma-separated \f(CWWORD\fP's.  The
  495. \f(CW("," WORD)*\fP construction says match zero or more \f(CW","\ WORD\fP
  496. sequences.  Consider,
  497. .cB
  498. st  :   "if" expr "then" st {"else" st} ";"
  499.     |   WORD ":=" expr
  500.     |    "begin" ( st ";" )+ "end"
  501.     ;
  502. .cE
  503. .LP
  504. where \f(CWexpr\fP is some rule that matches an arithmetic
  505. expression.  Rule \f(CWst\fP matches statements such as:
  506. .cB
  507. if $expr sub 1$ then begin
  508.   i := $expr sub 2$;
  509.   j := $expr sub 3$;
  510. end
  511. else
  512.   k := $expr sub 4$;
  513. .cE
  514. .LP
  515. The first alternative has an optional subrule that matches an
  516. \f(CWelse\fP-clause if it exists.  The third alternative matches one or more
  517. semicolon-delimited statements, which are enclosed in \f(CWbegin\fP and
  518. \f(CWend\fP.  Let's examine the description of a simple expression.
  519. .cB
  520. e   :   e1 ( ("\e+" | "\e-") e1 )*
  521.     ;
  522.  
  523. e1  :   WORD
  524.     |   INT
  525.     ;
  526. .cE
  527. .LP
  528. Rule \f(CWe\fP matches simple expressions with only plus and minus as
  529. operators; e.g. \f(CWa+3-b\fP or \f(CWa\fP.  Note that we have nested the
  530. \f(CW("\e+" | "\e-")\fP subrule within the \f(CW(...)*\fP subrule.
  531. .PP
  532. Let's build a complete PCCTS language description by extending the
  533. expression example.  Rules to handle multiplication and division will be
  534. added as well as token definitions to ignore white space etc...:
  535. .cB
  536. #header <<#include "charbuf.h">>
  537.  
  538. <<main() { ANTLR(calc(), stdin); }>>
  539.  
  540. #token     "[\e \et]"  <<zzskip();>>           /* ignore blanks, tabs */
  541. #token     "\en"      <<zzline++;>>           /* ignore newlines */
  542. #token INT "[0-9]+"
  543. #token FLOAT "[0-9]+ {. [0-9]+}"
  544.  
  545. calc:   ( e "\en" )* "@"
  546.     ;
  547.  
  548. e   :   e1 ( ("\e+" | "\e-") e1 )*
  549.     ;
  550.  
  551. e1  :   e2 ( ("\e*" | "/") e2 )*
  552.     ;
  553.  
  554. e2  :   INT
  555.     |    FLOAT
  556.     ;
  557. .cE
  558. .LP
  559. Note that newlines are no longer to be ignored, hence, the \f(CWzzskip()\fP
  560. function call has been removed from its lexical action.  Our language is a
  561. set of expressions terminated by newlines followed by end-of-file (\f(CW@\fP
  562. is a predefined lexical meta-symbol referring to end-of-file).  Without
  563. actions, testing this grammar is uninteresting because no output is
  564. generated (unless, of course, an invalid expression is given).  Therefore,
  565. let us place an action among the rule elements to generate some output.
  566. Augment rule \f(CWcalc\fP as follows:
  567. .cB
  568. calc:   ( e "\en" <<printf("found expression\en");>> )* "@"
  569.     ;
  570. .cE
  571. .LP
  572. Essentially, we have added C code to print out a brief message after an
  573. expression-newline pair has been encountered.  Create the executable,
  574. \f(CWt\fP, as before with:
  575. .cB
  576. antlr -gk t.g
  577. dlg -i parser.dlg scan.c
  578. cc -I../h -o t t.c scan.c err.c
  579. .cE
  580. .LP
  581.  
  582. Test the program via a few simple expressions:
  583. .cB
  584. % t
  585. 3+4*5
  586. found expression
  587. 3.15 / 6 - 2.1
  588. found expression
  589. ^D% 
  590. .cE
  591. .LP
  592. This example grammar is not recursive; i.e. no rule references another
  593. rule that directly or indirectly returns to itself.  But, recursion is
  594. a very powerful tool.  It allows the concept of
  595. \fIself-similarity\fP.  In other words, structures in which some
  596. subcomponents are similar to the outer structure.  Pascal has several
  597. self-similar constructs: record field definitions, procedure
  598. definitions, expressions, and type definitions to name a few.
  599. .PP
  600. To illustrate recursive grammars, we extend the above expression example to
  601. allow parenthesized subexpressions such as \f(CW(3+4)*7\fP.
  602. .cB
  603. e2  :   INT
  604.     |    FLOAT
  605.     |   "\e(" e "\e)"
  606.     ;
  607. .cE
  608. .LP
  609. Placing the subexpression construct at the lowest recursion level makes it
  610. have the highest precedence because of the nature of top-down, depth-first
  611. parsing.  To see this, consider the parse tree for \f(CW(3+4)*5\fP
  612. (beginning at rule \f(CWe\fP):
  613. .KS
  614. .PS
  615. .ps 11
  616. box invis "\f(CWe\fP" with .sw at (2.24,9.76) width 0.25 height 0.25
  617. box invis "\f(CWe2\fP" with .sw at (2.24,9.26) width 0.25 height 0.25
  618. box invis "\f(CWe3\fP" with .sw at (1.74,8.76) width 0.25 height 0.25
  619. box invis "\f(CW*\fP" with .sw at (2.24,8.76) width 0.25 height 0.25
  620. box invis "\f(CW5\fP" with .sw at (2.74,8.76) width 0.25 height 0.25
  621. box invis "\f(CWe\fP" with .sw at (1.74,8.26) width 0.25 height 0.25
  622. box invis "\f(CW(\fP" with .sw at (1.24,8.26) width 0.25 height 0.25
  623. box invis "\f(CW)\fP" with .sw at (2.24,8.26) width 0.25 height 0.25
  624. box invis "\f(CW3\fP" with .sw at (1.24,7.76) width 0.25 height 0.25
  625. box invis "\f(CW+\fP" with .sw at (1.74,7.76) width 0.25 height 0.25
  626. box invis "\f(CW4\fP" with .sw at (2.24,7.76) width 0.25 height 0.25
  627. line -> from 2.362,9.762 to 2.362,9.512
  628. line -> from 2.362,9.262 to 2.362,9.012
  629. line -> from 2.362,9.262 to 1.863,9.012
  630. line -> from 2.362,9.262 to 2.862,9.012
  631. line -> from 1.863,8.762 to 1.863,8.512
  632. line -> from 1.863,8.762 to 1.363,8.512
  633. line -> from 1.863,8.762 to 2.362,8.512
  634. line -> from 1.863,8.262 to 1.363,8.012
  635. line -> from 1.863,8.262 to 1.863,8.012
  636. line -> from 1.863,8.262 to 2.362,8.012
  637. .PE
  638. .KE
  639. .LP
  640. Clearly, \f(CW3+4\fP must be evaluated before the \f(CW*\fP for a valid
  641. result; this is precisely a depth-first evaluation of the parse tree (which
  642. PCCTS parsers do naturally).  The deeper the recursive nesting, the higher
  643. the precedence.  Extending the input expression to \f(CW(3+4)*(5-6)\fP
  644. yields:
  645. .KS
  646. .PS
  647. .ps 11
  648. box invis "\f(CWe3\fP" with .sw at (1.24,6.01) width 0.25 height 0.25
  649. box invis "\f(CWe\fP" with .sw at (1.24,5.51) width 0.25 height 0.25
  650. box invis "\f(CW(\fP" with .sw at (0.74,5.51) width 0.25 height 0.25
  651. box invis "\f(CW)\fP" with .sw at (1.74,5.51) width 0.25 height 0.25
  652. box invis "\f(CW3\fP" with .sw at (0.74,5.01) width 0.25 height 0.25
  653. box invis "\f(CW+\fP" with .sw at (1.24,5.01) width 0.25 height 0.25
  654. box invis "\f(CW4\fP" with .sw at (1.74,5.01) width 0.25 height 0.25
  655. line -> from 1.363,6.013 to 1.363,5.763
  656. line -> from 1.363,6.013 to 0.863,5.763
  657. line -> from 1.363,6.013 to 1.863,5.763
  658. line -> from 1.363,5.513 to 0.863,5.263
  659. line -> from 1.363,5.513 to 1.363,5.263
  660. line -> from 1.363,5.513 to 1.863,5.263
  661. box invis "\f(CWe3\fP" with .sw at (3.24,6.01) width 0.25 height 0.25
  662. box invis "\f(CWe\fP" with .sw at (3.24,5.51) width 0.25 height 0.25
  663. box invis "\f(CW(\fP" with .sw at (2.74,5.51) width 0.25 height 0.25
  664. box invis "\f(CW)\fP" with .sw at (3.74,5.51) width 0.25 height 0.25
  665. box invis "\f(CW5\fP" with .sw at (2.74,5.01) width 0.25 height 0.25
  666. box invis "\f(CW-\fP" with .sw at (3.24,5.01) width 0.25 height 0.25
  667. box invis "\f(CW6\fP" with .sw at (3.74,5.01) width 0.25 height 0.25
  668. line -> from 3.362,6.013 to 3.362,5.763
  669. line -> from 3.362,6.013 to 2.862,5.763
  670. line -> from 3.362,6.013 to 3.862,5.763
  671. line -> from 3.362,5.513 to 2.862,5.263
  672. line -> from 3.362,5.513 to 3.362,5.263
  673. line -> from 3.362,5.513 to 3.862,5.263
  674. box invis "\f(CWe\fP" with .sw at (2.24,7.01) width 0.25 height 0.25
  675. box invis "\f(CWe2\fP" with .sw at (2.24,6.51) width 0.25 height 0.25
  676. box invis "\f(CW*\fP" with .sw at (2.24,6.01) width 0.25 height 0.25
  677. line -> from 2.362,7.013 to 2.362,6.763
  678. line -> from 2.362,6.513 to 2.362,6.263
  679. line -> from 2.362,6.513 to 1.363,6.263
  680. line -> from 2.362,6.513 to 3.362,6.263
  681. .PE
  682. .KE
  683. .LP
  684. Again, both operands of the \f(CW*\fP must be evaluated before it can
  685. proceed.
  686. .PP
  687. As another example of recursive definitions, consider type definitions for a
  688. Pascal-like language.  Types look like:
  689. .cB
  690. char
  691. integer
  692. array [5] of char
  693. array [100] of array [20] of integer
  694. .cE
  695. .LP
  696. A grammar similar to the following could be used:
  697. .cB
  698. type:   "char"
  699.     |   "integer"
  700.     |   "array" "\e[" INT "\e]" "of" type
  701.     ;
  702. .cE
  703. The recursive invocation of \f(CWtype\fP by the \f(CWarray\fP alternative
  704. effectively allows chains of \f(CWarray\fP specifications.  The parse tree
  705. for
  706. .cB
  707. array [100] of array [20] of integer
  708. .cE
  709. .LP
  710. looks like:
  711. .KS
  712. .PS
  713. .ps 11
  714. box invis "\f(CW[\fP" with .sw at (2.49,8.76) width 0.25 height 0.25
  715. box invis "\f(CWarray\fP" with .sw at (1.99,8.76) width 0.25 height 0.25
  716. box invis "\f(CW20\fP" with .sw at (2.99,8.76) width 0.25 height 0.25
  717. box invis "\f(CW]\fP" with .sw at (3.49,8.76) width 0.25 height 0.25
  718. box invis "\f(CWof\fP" with .sw at (3.99,8.76) width 0.25 height 0.25
  719. box invis "\f(CWtype\fP" with .sw at (4.49,8.76) width 0.25 height 0.25
  720. line -> from 3.362,9.262 to 2.112,9.012
  721. line -> from 3.362,9.262 to 2.612,9.012
  722. line -> from 3.362,9.262 to 3.112,9.012
  723. line -> from 3.362,9.262 to 3.612,9.012
  724. line -> from 3.362,9.262 to 4.112,9.012
  725. line -> from 3.362,9.262 to 4.612,9.012
  726. box invis "\f(CWtype\fP" with .sw at (3.24,9.26) width 0.25 height 0.25
  727. box invis "\f(CW[\fP" with .sw at (1.24,9.26) width 0.25 height 0.25
  728. box invis "\f(CWarray\fP" with .sw at (0.74,9.26) width 0.25 height 0.25
  729. box invis "\f(CW100\fP" with .sw at (1.74,9.26) width 0.25 height 0.25
  730. box invis "\f(CW]\fP" with .sw at (2.24,9.26) width 0.25 height 0.25
  731. box invis "\f(CWof\fP" with .sw at (2.74,9.26) width 0.25 height 0.25
  732. box invis "\f(CWtype\fP" with .sw at (1.99,9.76) width 0.25 height 0.25
  733. line -> from 2.112,9.762 to 0.863,9.512
  734. line -> from 2.112,9.762 to 1.363,9.512
  735. line -> from 2.112,9.762 to 1.863,9.512
  736. line -> from 2.112,9.762 to 2.362,9.512
  737. line -> from 2.112,9.762 to 2.862,9.512
  738. line -> from 2.112,9.762 to 3.362,9.512
  739. box invis "\f(CWinteger\fP" with .sw at (4.49,8.26) width 0.25 height 0.25
  740. line -> from 4.612,8.762 to 4.612,8.512
  741. .PE
  742. .KE
  743. .LP
  744. In this case, we are less interested in precedence and more interested in
  745. allowing chains of array specifications.
  746. .PP
  747. In general, recursion and repetition constructs such as \f(CW(...)+\fP are
  748. needed to avoid delineating all possible phrases in a language.  Grammars
  749. are descriptions of the patterns found among the phrases of a particular
  750. language just as $size +2 SIGMA$ notation summarizes an infinite series.
  751. .PP
  752. The recognition of input languages, via the use of grammars, performs two
  753. tasks: it ensures phrase validity and directs translation to an output
  754. language.  The next section demonstrates how actions, embedded among the
  755. grammar elements, can be used to effect a translation.
  756. .NH
  757. .iH Translation
  758. .PP
  759. Given a grammar, PCCTS constructs a recognizer for phrases in that input
  760. language.  No translation from input to output is performed.  User actions
  761. must be supplied in the correct positions to generate output.  Translation
  762. occurs when an action produces output which is a function of the input
  763. phrase.  Actions have access to input phrase token values through an
  764. abstraction called an \fIattribute\fP.  These attributes are user-defined
  765. types and can be as simple as the text associated with a token.
  766. .PP
  767. This section introduces the notion of an attribute as a means of
  768. communicating with the lexical analyzer and presents a number of examples
  769. that explain how and where actions can be used to generate output.
  770. .NH 2
  771. .iH Attributes
  772. .PP
  773. Attributes are objects associated with all rules and rule elements,
  774. but we will only concern ourselves here with attributes associated
  775. with token and rule references.  Attributes are referenced in actions
  776. with the notation \f(CW\*d\fP$i$ where $i$ indicates that the
  777. attribute for the $i sup th$ token in that production is desired.
  778. Attributes are run-time objects and have no value until run-time.
  779. They are generally used to access the actual text (or a function of
  780. the text) of the tokens matched on the input stream.  The set of all
  781. tokens defines the \fIvocabulary\fP of the input language.  The term
  782. \*Qtoken\*U collectively refers to the token type (an integer that
  783. identifies it as part of the vocabulary) and the token text (the
  784. actual string that matched the regular expression for the token
  785. type).
  786. .PP
  787. Before illustrating attributes, we begin with an example.  The
  788. vocabulary of an input language (known a priori) may be the set {
  789. \f(CWWORD\fP, \f(CW"begin"\fP, \f(CWINT\fP }, which is the set of
  790. integer token types.  The text associated with a token type is only
  791. known at parser run-time because it depends on the input characters.
  792. Let us say that the grammatical structure of the language is any
  793. sequence of tokens in the vocabulary (ignoring white space); then, a
  794. valid sentence could be:
  795. .cB
  796. begin hello 34 13 bob
  797. .cE
  798. .LP
  799. The parser would see a token stream of tuples of the form (token type,
  800. token text):
  801. .cB
  802. (begin, begin)
  803. (WORD, hello)
  804. (INT, 34)
  805. (INT, 13)
  806. (WORD, bob)
  807. .cE
  808. .LP
  809. A different input sentence, with the same sequence of \fBtoken
  810. types\fP is:
  811. .cB
  812. begin hi 2 99 ptr
  813. .cE
  814. .LP
  815. which would yield the same sequence of token types, but a different
  816. set of token text:
  817. .cB
  818. (begin, begin)
  819. (WORD, hi)
  820. (INT, 2)
  821. (INT, 99)
  822. (WORD, ford)
  823. .cE
  824. The grammar might look like:
  825. .cB
  826. a : ( WORD | "begin" | INT )+
  827.   ;
  828. .cE
  829. .LP
  830. Only the token types are referenced in the grammar as they describe
  831. the structure of the language and are a shorthand notation for the set
  832. of valid input sentences.  Obviously, one could not delineate all
  833. possible sentences as there are infinitely many.  For a PCCTS
  834. description to perform a translation that is specific to the
  835. particular input, actions must access the text of the input tokens,
  836. not just the token type.  Attributes are provided to provide access to
  837. the text (or some function thereof) of an input token.  To illustrate
  838. this, we give a complete example and then, later, describe the
  839. particulars:
  840. .cB
  841. #header <<#include "charptr.h">>
  842.  
  843. <<main() { ANTLR(a(), stdin); }>>
  844.  
  845. #token "[\e \et]"        <<zzskip();>>
  846. #token "\en"            <<zzline++; zzskip();>>
  847.  
  848. a : ( WORD    <<printf(" %s", \*d1);>>
  849.     | "begin" <<printf(" begin");>>
  850.     | INT     <<printf(" %s", \*d1);>>
  851.     )+
  852.   ;
  853.  
  854. #token WORD "[a-z]+"
  855. #token INT  "[0-9]+"
  856. .cE
  857. .LP
  858. This example defines attributes to be strings representing what was
  859. found on the input stream and prints the stream of tokens back out.
  860. In other words, attributes are merely a copy of the words found; the
  861. mapping from token/lexeme to attribute is an identity mapping (do
  862. nothing but copy).  For the moment, concentrate on the actions.
  863. \f(CW\*d1\fP refers to the attribute of the first item in the
  864. production in which the action occurs; in this case, only one item
  865. appears per production.  Note that the action for the \f(CW"begin"\fP
  866. token does not need to refer to its attribute as it will always be
  867. \f(CWbegin\fP.  The rest of this section describes the particulars
  868. needed to understand everything else in the example.
  869. .PP
  870. PCCTS requires that the user define the data type or structure of the
  871. attributes as well as specify how to convert from lexemes to
  872. attributes.  The type is always defined by a C \f(CWtypedef\fP named
  873. \f(CWAttrib\fP and must be defined in the action associated with the
  874. \f(CW#header\fP instruction.  For example, if one wishes the attribute
  875. for a token to be simple integers, the following is a sufficient type
  876. definition:
  877. .cB
  878. #header <<typedef int Attrib;>>
  879. .cE
  880. .LP
  881. However, this does not tell PCCTS how to convert a token to an attribute.
  882. This is accomplished with a function called \f(CWzzcr_attr()\fP which defines
  883. the value of an attribute given complete information about a lexeme (token
  884. number and associated text).  It has the general form:
  885. .cB
  886. void
  887. zzcr_attr(a,token,text)
  888. Attrib *a;
  889. int token;
  890. char *text;
  891. {
  892.     /* *a = function(token, text); */
  893. }
  894. .cE
  895. where \f(CWa\fP points to an attribute created by PCCTS at run-time.  The
  896. user simply has to assign a value to \f(CW*a\fP.  In our case, we will use a
  897. macro version to set our attributes to the integer value of the input:
  898. .cB
  899. #define zzcr_attr(a,tok,txt) {*(a) = atoi(txt);}
  900. .cE
  901. .LP
  902. This specifies that whenever a token is matched on the input stream by
  903. the parser, an attribute of type \f(CWint\fP is to be created and
  904. assigned the result of \f(CWatoi(\fItext\f(CW)\fR where \fItext\fP is
  905. the character string matched for the token.  The attribute is then made
  906. available as \f(CW\*d\fP$i$ to actions in the production that matched
  907. the token.  For example,
  908. .cB
  909. #header <<
  910.     typedef int Attrib;
  911.     #define zzcr_attr(a,tok,txt) {*(a) = atoi(txt);}
  912. >>
  913.  
  914. <<main() { ANTLR(a(), stdin); }>>
  915.  
  916. #token "[\e \et]"        <<zzskip();>>
  917. #token "\en"            <<zzline++; zzskip();>>
  918.  
  919. a   :   "hi" "[0-9]+" <<printf("\*d1, \*d2 are %d, %d\en", \*d1, \*d2);>>
  920.     ;
  921. .cE
  922. .LP
  923. \f(CW\*d1\fP refers to the first token in the alternative,
  924. \f(CW"hi"\fR; similarly, \f(CW\*d2\fP refers to the the second token,
  925. \f(CW"[0-9]+"\fR.  When executed, the executable \f(CWt\fP (created as
  926. before) yields:
  927. .cB
  928. % t
  929. hi 34
  930. \*d1, \*d2 are 0, 34
  931. .cE
  932. .LP
  933. where \f(CWatoi()\fP of a non-numeric string is 0, but the text
  934. \f(CW34\fP gets converted to an integer (binary word) version of 34
  935. and printed back out as a number.
  936. .PP
  937. The token type can be tested to ensure that it is an integer before
  938. applying the \f(CWatoi()\fP function via:
  939. .cB
  940. #header <<
  941.     typedef int Attrib;
  942.     #define zzcr_attr(a,tok,txt) {if ( tok==INT ) *(a) = atoi(txt);}
  943. >>
  944. .cE
  945. .LP
  946. where \f(CWINT\fP is defined to be \f(CW"[0-9]+"\fR.  This defines an
  947. attribute for all \f(CWINT\fP tokens found on the input stream.  Other
  948. tokens have undefined attributes.
  949. .PP
  950. Attributes can have multiple elements or assume one of many values.  For
  951. example, we can extend the above example to handle \f(CWFLOAT\fP tokens as
  952. well:
  953. .cB
  954. #header <<typedef union { int ival; float fval; } Attrib;>>
  955. .cE
  956. .cB
  957. <<
  958. void
  959. zzcr_attr(a,token,text)
  960. Attrib *a;
  961. int token;
  962. char *text;
  963. {
  964.     switch ( token )
  965.     {
  966.         case INT   : (a)->ival = atoi(text); break;
  967.         case FLOAT : (a)->fval = atof(text); break;
  968.     }
  969. }
  970. >>
  971. .cE
  972. .LP
  973. The \f(CWtypedef\fP specifies that attributes are integer or floating
  974. point values.  When the regular expression for a floating point number
  975. (integer number) is matched on the input stream, \f(CWzzcr_attr()\fP
  976. converts the string of characters representing that number to a C
  977. \f(CWfloat\fP (\f(CWint\fP).
  978. .PP
  979. Attributes can become even more complicated, but typically, attributes
  980. are merely a copy of the text found on the input stream.  A standard
  981. PCCTS attribute definition is available as \f(CWcharbuf.h\fP and is
  982. defined as follows:
  983. .cB
  984. /* PCCTS attribute -- constant width text */
  985. #ifndef D_TextSize
  986. #define D_TextSize    30
  987. #endif
  988.  
  989. typedef struct { char text[D_TextSize]; } Attrib;
  990.  
  991. #define zzcr_attr(a,tok,t)    strncpy((a)->text, t, D_TextSize-1);
  992. .cE
  993. .LP
  994. These attributes are referred to by \f(CW\*d\fP$i$\f(CW.text\fP in actions.
  995. .PP
  996. Each alternative begins a new sequence of \f(CW\*d\fP$i$'s and from an
  997. enclosing scope/level, entire subules are counted as one unit.  This is best
  998. explained with an example:
  999. .cB
  1000. a   :   A B ( C D )+ E
  1001.     |   F G
  1002.     ;
  1003. .cE
  1004. .LP
  1005. From an action after token \f(CWE\fP, \f(CWA\fP is \f(CW\*d1\fP, \f(CWB\fP
  1006. is \f(CW\*d2\fP, the entire subrule \f(CW( C D )\fP is \f(CW\*d3\fP, and
  1007. \f(CWE\fP is \f(CW\*d4\fP; \f(CWC\fP and \f(CWD\fR are inaccessible from
  1008. outside the scope of the subrule.  From an action inside the subrule just
  1009. after the token \f(CWD\fP, \f(CWC\fP is \f(CW\*d1\fP and \f(CWD\fP is
  1010. \f(CW\*d2\fP.  In alternative two from an action after \f(CWG\fP, \f(CWF\fP
  1011. is \f(CW\*d1\fP and \f(CWF\fP is \f(CW\*d2\fP.  Attributes have a scoping
  1012. just like variables in a programming langauage.
  1013. .PP
  1014. Attributes are a means of communicating with the lexical analyzer.  Actions
  1015. may use these attributes to provide a translation.  The next section
  1016. utilizes the concepts presented here to build translators.
  1017. .NH 2
  1018. .iH Actions
  1019. .PP
  1020. Actions are rule elements just like token references, but perform a
  1021. different function.  Token references indicate that a particular token is to
  1022. be matched on the input stream at that point in the parse.  Actions indicate
  1023. that this action is to be performed at that point in the parse, immediately
  1024. following the preceding token match.  For example,
  1025. .cB
  1026. a   :   A <<$action sub 1$>> B ;
  1027.     |  ( C )+ <<$action sub 2$>>
  1028.     ;
  1029. .cE
  1030. .LP
  1031. $action sub 1$ is executed after the parser has found an \f(CWA\fP, but
  1032. before it has found a \f(CWB\fP.  $action sub 2$ is executed only after a
  1033. sequence of one or more \f(CWC\fP's has been found.
  1034. .PP
  1035. As a more concrete example, we augment the above \f(CWcalc\fP example to
  1036. print something more useful than \f(CWfound expression\fP:
  1037. .cB
  1038. calc:   ( e "\en" <<printf("\en");>> )* "@"
  1039.     ;
  1040.  
  1041. e   :   e1
  1042.         (   (  "\e+" <<printf(" add");>>
  1043.             |  "\e-" <<printf(" sub");>>
  1044.             )
  1045.             e1
  1046.         )*
  1047.     ;
  1048. .cE
  1049. .cB
  1050. e1  :   e2
  1051.         (   (  "\e*" <<printf(" mult");>>
  1052.             |  "/"   <<printf(" div");>>
  1053.             )
  1054.             e2
  1055.         )*
  1056.     ;
  1057.  
  1058. e2  :   INT     <<printf(" INT");>>
  1059.     |    FLOAT   <<printf(" FLOAT");>>
  1060.     ;
  1061. .cE
  1062. .LP
  1063. Essentially, we have added C code to print out the operand types and
  1064. operators.  Create the executable, \f(CWt\fP, as before with
  1065. .cB
  1066. antlr -gk t.g
  1067. dlg -i parser.dlg scan.c
  1068. cc -I../h -o t t.c scan.c err.c
  1069. .cE
  1070. .LP
  1071. Test the program via a few simple expressions:
  1072. .cB
  1073. % t
  1074. 3+4*5
  1075.  INT add INT mult INT
  1076. 3.15 / 6 - 2.1
  1077.  FLOAT div INT sub FLOAT
  1078. ^D% 
  1079. .cE
  1080. .LP
  1081. Now, let's use the attributes to generate code for a simple
  1082. \fIreverse-polish\fP stack machine whose operations are defined as follows:
  1083. .IP "\f(CWpush $opnd$\fR"
  1084. Push $opnd$ onto the stack.
  1085. .IP "\f(CWprint\fR"
  1086. Print the value of the top of stack; POP the value off the stack.
  1087. .IP "\f(CWadd\ \ \ \fR"
  1088. PUSH(POP + POP)
  1089. .IP "\f(CWsub\ \ \ \fR"
  1090. $a$ := POP
  1091. .br
  1092. $b$ := POP
  1093. .br
  1094. PUSH($b$ - $a$)
  1095. .IP "\f(CWmult\ \ \ \fR"
  1096. PUSH(POP * POP)
  1097. .IP "\f(CWdiv\ \ \ \fR"
  1098. $a$ := POP
  1099. .br
  1100. $b$ := POP
  1101. .br
  1102. PUSH($b$ / $a$)
  1103. .LP
  1104. Modify the rules as follows:
  1105. .cB
  1106. #header <<#include "charbuf.h">>
  1107.  
  1108. <<main() { ANTLR(calc(), stdin); }>>
  1109.  
  1110. #token     "[\e \et]"  <<zzskip();>>           /* ignore blanks, tabs */
  1111. #token     "\en"      <<zzline++;>>           /* ignore newlines */
  1112. #token INT "[0-9]+"
  1113. #token FLOAT "[0-9]+ {. [0-9]+}"
  1114. .cE
  1115. .cB
  1116. calc:   ( e "\en" <<printf("\etprint\en");>> )* "@"
  1117.     ;
  1118.  
  1119. e   :   <<char *op;>>
  1120.         e1
  1121.         (   (  "\e+" <<op="\etadd\en";>>
  1122.             |  "\e-" <<op="\etsub\en";>>
  1123.             )
  1124.             e1
  1125.             <<printf("%s", op);>>
  1126.         )*
  1127.     ;
  1128. .cE
  1129. .cB
  1130. e1  :   <<char *op;>>
  1131.         e2
  1132.         (   (  "\e*"  <<op="\etmult\en";>>
  1133.             |  "/"   <<op="\etdiv\en";>>
  1134.             )
  1135.             e2
  1136.             <<printf("%s", op);>>
  1137.         )*
  1138.     ;
  1139.  
  1140. e2  :   INT     <<printf("\etpush %s\en", \*d1.text);>>
  1141.     |    FLOAT   <<printf("\etpush %s\en", \*d1.text);>>
  1142.     ;
  1143. .cE
  1144. .LP
  1145. .bp
  1146. .EF ''''
  1147. .OF ''''
  1148. .LP
  1149. .PX
  1150.